package dao.jpa;

import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import dao.GenericDao;
import domain.impl.AbstractBusinessObject;
import org.springframework.beans.factory.annotation.Autowired;
import util.PersistenceUtils;
import vo.ValueObject;


public abstract class GenericJpaDao<T extends AbstractBusinessObject, V extends ValueObject> implements GenericDao<T,V> {

         //TODO ver porque es necesario castear en los metodos del PersistenceUtils

        @PersistenceContext
        private EntityManager em;
        @Autowired
        private PersistenceUtils persistenceUtils;

        private Class<T> businesObjectClass;
        private Class<V> valueObjectClass;

        public Class<T> getBusinessObjectClass() {
                return businesObjectClass;
        }

        public Class<V> getValueObjectClass() {
                return valueObjectClass;
        }

        @SuppressWarnings("unchecked")
        public GenericJpaDao() {
             this.businesObjectClass = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
             this.valueObjectClass = (Class<V>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[1];
         }

        public int countAll() {
            Query query = em.createQuery("select p from "+businesObjectClass.getName()+ " p");
            return query.getResultList().size();
        }

        public void delete(T businessObject) {
            //em.remove(persistenceUtils.build(valueObject));
            em.remove(businessObject);
        }

        public List<T> findAll() {
            Query query = em.createQuery("select p from "+businesObjectClass.getName()+ " p");
            return query.getResultList();
        }

        public List<T> findByNamedQuery(Object[] params, String name) {
           Query query = em.createQuery(name);
           for (int i=0;i<params.length;i++) query.setParameter(i,params[i]);
           return query.getResultList();
        }

        public List<T> findByNamedQueryAndNamedParams(Map<String, Object> params,
                        String name) {
           Query query = em.createQuery(name);
           for (String key : params.keySet()) query.setParameter(key, params.get(key));

           return query.getResultList();
        }

        @SuppressWarnings("unchecked")
        public T findByPrimaryKey(Long primaryKey) {
            return (T) em.find(businesObjectClass, primaryKey.intValue());
        }

        public void update(T businessObject) {
            em.clear();
            em.persist(businessObject);
        }

        public void create(T businessObject) {
            em.merge(businessObject);
            em.flush();
        }


        /*@SuppressWarnings("unchecked")
        private List<V> getResultListObject(Query query) {
                List<V> vos = new ArrayList<V>();
                List<T> bos =
                for (T bo : bos) {
                        vos.add((V)persistenceUtils.build(bo, null));
                }
                return vos;
        }*/




}